#include <Arduino.h>
#include "base64.h"
#include <WiFi.h>
#include <I2S.h>
#include <ArduinoJson.h>
#include <SoftwareSerial.h>
#include "esp_task_wdt.h"
#include "Gpt.h"
#include "Tts.h"
#include "Image.h"

#define MYPORT_TX 1
#define MYPORT_RX 2

uint8_t voicedata[] = {0xFD, 0x00, 0x06, 0x01, 0x01, 0x5B, 0x76, 0x31, 0x5D}; // voicedata[7] =  0x31 ~ 0x39

// 1. Replace with your network credentials
// const char *ssid = "Doctor's_home";
// const char *password = "115115115";
const char *ssid = "IQOO";
const char *password = "12345678";
// 2. Check your Aduio port
const int buttonPin = 9;     // the number of the pushbutton pin
#define SHORT_PRESS_TIME 100 // 短按时间阈值，单位为毫秒
#define LONG_PRESS_TIME 400  // 长按时间阈值，单位为毫秒

static int count = 0;
static unsigned long pressTime = 0;
static bool isPressed = false;
int buttonState = 1;
const int ledPin = 21; // the number of the LED pin
hw_timer_t *timer = NULL;

// uint16_t adc_data[data_len];    //16000个数据，8K采样率，即2秒，录音时间为2秒，想要实现更长时间的语音识别，就要改这个数组大小
// char data_json[json_len];          //用于储存json格式的数据,大一点,JSON编码后数据字节数变成原来的4/3,所以得计算好,避免出现越界
// 和下面data_json数组的大小，改大一些。
uint8_t adc_start_flag = 0;    // 开始标志
uint8_t adc_complete_flag = 0; // 完成标志

// Send request to MiniMax API
String inputText = "你好，minimax！";
String answer;

uint32_t num = 0;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer()
{
  // Increment the counter and set the time of ISR
  portENTER_CRITICAL_ISR(&timerMux);
  if (adc_start_flag == 1)
  {
    //  adc_data[num] = analogRead(ADC);
    adc_data[num] = I2S.read();
    num++;
    if (num >= adc_data_len)
    {
      adc_complete_flag = 1;
      adc_start_flag = 0;
      num = 0;
    }
  }
  portEXIT_CRITICAL_ISR(&timerMux);
}

void handleButtonPress()
{
  // 读取GPIO状态
  buttonState = digitalRead(buttonPin);

  if (buttonState == 0 && !isPressed)
  {
    // 按键按下
    isPressed = true;
    pressTime = millis();
  }
  else if (buttonState == 1 && isPressed)
  {
    // 按键释放
    isPressed = false;
    unsigned long releaseTime = millis();
    unsigned long pressDuration = releaseTime - pressTime;

    if (pressDuration >= LONG_PRESS_TIME)
    {
      // 长按
      buttonState = 3;
      Serial.println("Long press detected");
    }
    else if (pressDuration >= SHORT_PRESS_TIME)
    {
      // 短按
      buttonState = 2;
      count++;
      Serial.print("Short press detected, count: ");
      Serial.println(count);
    }
  }
}

void displayTask(void *parameter)
{
  for (;;)
  {
    if (xSemaphore != NULL)
    {
      xSemaphoreTake(xSemaphore, portMAX_DELAY);
      if (updateDisplayFlag)
      {
        scrollText(displayText.c_str());
        updateDisplayFlag = false;
      }
      xSemaphoreGive(xSemaphore);
    }
    vTaskDelay(200 / portTICK_PERIOD_MS); // 每秒检查一次
  }
}

void textTask(void *parameter)
{
  for (;;)
  {
    if (xSemaphore1 != NULL)
    {
      xSemaphoreTake(xSemaphore1, portMAX_DELAY);
      if (updateTextFlag)
      {
        smoothMoveServo(0, 180, 0); // 从0度转到180度，再回到0度
        updateTextFlag = false;
      }
      xSemaphoreGive(xSemaphore1);
    }
    vTaskDelay(10 / portTICK_PERIOD_MS); // 每秒检查一次
  }
}

void setup()
{
  // 启动看门狗定时器，超时时间为5秒
  esp_task_wdt_init(5, true);
  Serial.begin(115200);
  myPort.begin(115200, SWSERIAL_8N1, MYPORT_RX, MYPORT_TX, false);
  // 初始化I2C通信
  Wire.begin(7, 8); // 指定SDA和SCL引脚
  // 初始化U8g2库
  u8g2.begin();
  u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function
  // 显示文本
  u8g2.clearBuffer();                     // 清除缓冲区
  u8g2.setFont(u8g2_font_wqy12_t_gb2312); // 设置字体
  u8g2.setFontDirection(0);
  u8g2.firstPage();
  u8g2.clearBuffer(); // 清除缓冲区
  u8g2.setCursor(20, 16);
  u8g2.print("XIAO智能助手");
  u8g2.sendBuffer(); // 将缓冲区内容发送到屏幕
  delay(1000);
  if (!myPort)
  { // If the object did not initialize, then its configuration is invalid
    Serial.println("Invalid EspSoftwareSerial pin configuration, check config");
    while (1)
    { // Don't continue with invalid configuration
      delay(1000);
    }
  }
  while (workstate() > 0)
  {
    delay(1000);
  }
  speech("系统开机");
  delay(1500);
  for (int i = 0; i < sizeof(voicedata) / sizeof(voicedata[0]); i++)
  {
    myPort.write(voicedata[i]);
  }
  delay(1000);
  speech("音量以调小");
  adc_data = (uint16_t *)ps_malloc(adc_data_len * sizeof(uint16_t)); // ps_malloc 指使用片外PSRAM内存
  memset(adc_data, '\0', adc_data_len * sizeof(uint16_t));
  if (!adc_data)
  {
    Serial.println("Failed to allocate memory for adc_data");
    speech("无法分配PSRAM");
    while (1)
    {
      delay(1000);
    }
  }
  data_json = (char *)ps_malloc(data_json_len * sizeof(char)); // 根据需要调整大小
  memset(data_json, '\0', data_json_len * sizeof(char));
  if (!data_json)
  {
    Serial.println("Failed to allocate memory for data_json");
  }
  uint8_t count = 0;
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    count++;
    if (count >= 75)
    {
      Serial.printf("\r\n-- wifi connect fail! --");
      break;
    }
    vTaskDelay(200);
  }
  speech("已经连接网络");
  u8g2.setCursor(20, 32);
  u8g2.print("已经连接网络");
  u8g2.sendBuffer(); // 将缓冲区内容发送到屏幕
  Serial.printf("\r\n-- wifi connect success! --\r\n");
  Serial.println(WiFi.localIP());
  // baidu_token_key = getAccessToken(baidu_apiid, baidu_apisecret); // 本地鉴权，获取令牌
  baidu_token_key = "24.8d217475e5a695b3a8854ab49aa53c10.2592000.1732028538.282335-57722200";
  if (baidu_token_key != "")
  {
    speech("访问令牌成功");
    Serial.println(baidu_token_key);
    u8g2.setCursor(20, 48);
    u8g2.print("访问令牌成功");
    u8g2.sendBuffer(); // 将缓冲区内容发送到屏幕
  }
  else
  {
    speech("获取访问令牌失败");
    Serial.println("获取访问令牌失败");
    delay(5000);
    ESP.restart();
  }
  bool is_success = cam_intialization();
  if (is_success)
  {
    speech("摄像头初始化完成");
    Serial.println("摄像头初始化完成");
    u8g2.setCursor(10, 64);
    u8g2.print("摄像头初始化完成");
    u8g2.sendBuffer(); // 将缓冲区内容发送到屏幕
  }
  else
  {
    speech("摄像头初始化失败");
    delay(5000);
    ESP.restart();
  }

  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  // start I2S at 16 kHz with 16-bits per sample
  I2S.setAllPins(-1, 42, 41, -1, -1);
  if (!I2S.begin(PDM_MONO_MODE, 16000, 16))
  {
    Serial.println("Failed to initialize I2S!");
    while (1)
      ; // do nothing
  }
  timer = timerBegin(0, 80, true);   //  80M的时钟 80分频 1M
  timerAlarmWrite(timer, 125, true); //  1M  计125个数进中断  8K
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmEnable(timer);
  timerStop(timer); // 先暂停
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  servo1.setPeriodHertz(50);    // standard 50 hz servo
  servo1.attach(3, 1000, 2000); // Attach the servo after it has been detatched
  smoothMoveServo(0, 180, 0); // 从0度转到180度，再回到0度

  // 创建互斥锁
  xSemaphore = xSemaphoreCreateMutex();

  // 创建显示任务
  xTaskCreatePinnedToCore(
      displayTask,
      "Display Task",
      2048, // 栈大小
      NULL, // 任务参数
      1,    // 优先级
      NULL, // 任务句柄
      0);
  // xSemaphore1 = xSemaphoreCreateMutex();
  // // 创建显示任务
  // xTaskCreatePinnedToCore(
  //     textTask,
  //     "Text Task",
  //     1024, // 栈大小
  //     NULL, // 任务参数
  //     1,    // 优先级
  //     NULL, // 任务句柄
  //     0);
}

void loop()
{
  // 长时间操作前喂狗
  esp_task_wdt_reset();
  if (Serial.available())
  {
    GPT_change = Serial.read();
    switch (GPT_change)
    {
    case 'M':
      Serial.println("MiniMax");
      break;
    case 'D':
      Serial.println("Doubao");
      break;
    case 'B':
      Serial.println("Baidu");
      break;
    case 'A':
      Serial.println("Alibaba");
      break;
    default:
      Serial.println("Invalid input");
      break;
    }
  }

  handleButtonPress();
  if (buttonState == 2) // 按键按下
  {
    Serial.printf("Start recognition\r\n");
    digitalWrite(ledPin, HIGH);
    adc_start_flag = 1;
    timerStart(timer);

    while (!adc_complete_flag) // 等待采集完成
    {
      ets_delay_us(10);
    }

    timerStop(timer);
    adc_complete_flag = 0; // 清标志
    digitalWrite(ledPin, LOW);
    String baidu_voice_detection = sendToSTT();

    if (baidu_voice_detection != "error")
    {
      // 判断answer中是否包含灯或者机字符，如果有updateTextFlag变为true
      for (int i = 0; i < baidu_voice_detection.length(); i++)
      {
        if (baidu_voice_detection[i] == '灯' || baidu_voice_detection[i] == '机')
        {
          if (xSemaphore1 != NULL)
          {
            xSemaphoreTake(xSemaphore1, portMAX_DELAY);
            updateTextFlag = true;
            xSemaphoreGive(xSemaphore1);
          }
          digitalWrite(ledPin, HIGH);
          break;
        }
      }
      // 根据GPT_change选择不同的模型
      if (GPT_change == 'M')
      {
        Serial.println("MiniMax");
        answer = get_MiniMAX_Answer(baidu_voice_detection);
      }
      else if (GPT_change == 'D')
      {
        Serial.println("Doubao");
        answer = get_Doubao_Answer(baidu_voice_detection);
      }
      else if (GPT_change == 'B')
      {
        Serial.println("Baidu");
        answer = get_Baidu_Answer(baidu_voice_detection);
      }
      else if (GPT_change == 'A')
      {
        Serial.println("Ali");
        answer = get_Ali_Answer(baidu_voice_detection);
      }

      // 语音合成
      if (answer != "error")
      {

        word_cut(answer);

        // speech(answer);
        Serial.println("Answer: " + answer);
      }
      else
      {
        speech("GPT返回错误");
      }
    }
    else
    {
      speech("语音识别错误");
    }

    Serial.println("Recognition complete\r\n");
  }

  else if (buttonState == 3)
  {
    if (camera_sign)
    {
      // Save the image to the SD card
      String image_answer = image_request();
      if (image_answer != "error")
      {
        Serial.println("Image sent to OpenAI API, answer: " + image_answer);
        word_cut(image_answer);
      }
    }
    // 长时间操作前喂狗
    esp_task_wdt_reset();
  }

  vTaskDelay(1);
}
